"""
IO 操作之 文件读写
"""

# 1. 引入标准库的 os 模块
import os

# getcwd() 查看当前工作目录
getcwd = os.getcwd()
print(getcwd)

# 2. open(name[, mode[, buffering]]) 函数用于打开一个文件，创建一个 file 对象，相关的方法才可以调用它进行读写。

#   name : 一个包含了你要访问的文件名称的字符串值；
#   mode : mode 决定了打开文件的模式：只读，写入，追加等。这个参数是非强制的，默认文件访问模式为只读(r)。具体见：
#          https://www.runoob.com/python/python-func-open.html ；
#   buffering : 如果 buffering 的值被设为 0，就不会有寄存。如果 buffering 的值取 1，访问文件时会寄存行。如果将 buffering 的值设为大于 1
#   的整数，表明了这就是的寄存区的缓冲大小。如果取负值，寄存区的缓冲大小则为系统默认；

# 3. w模式 - 打开一个文件只用于写入。如果该文件已存在则打开文件，并从开头开始编辑，即原有内容会被删除。如果该文件不存在，创建新文件
t = open('test.txt', 'w')
size = t.write('43434343434343')
print('写入文件内容长度：{0}'.format(size))
# 关闭文件
t.close()
# 再次以 w模式 打开，可以看到原内容 '43434343434343' 被删除
text_io = open('test.txt', 'w')
text_io.write('advfghrtrtertrtrt1\n')
text_io.write('advfghrtrtertrtrt2\n')
text_io.write('advfghrtrtertrtrt3\n')
text_io.close()

# 4. read([size])：size 未指定则返回整个文件，但是需要注意，如果文件大小大于 2倍内存则有问题。f.read()读到文件尾时返回''(空字串)
open1 = open('test.txt')
read = open1.read()
print('读取内容为：%s' % read)

# 5. readline([limit])：limit 未指定则返回一行。limit 如果指定则不一样了，一般不这么用
open2 = open('test.txt')
print(open2.readline())
print(open2.readline())
print(open2.readline())
# 所有读取完毕后，如果再调用将返回 ''
readline = open2.readline()
print(readline)

# 6. readlines([size]) ：返回包含size行的列表, size 未指定则返回全部行
open3 = open('test.txt')
print(open3.readlines())
# 再次读取返回一个空列表
print(open3.readlines())

# 7. 通过循环读取文件
open4 = open('test.txt')
for line in open4:
    print('通过循环读取文件内容：%s' % line)

# 8. with 上下文管理。其实是try-finally的简写形式。但是又不是全相同

# a模式 - 打开一个文件用于追加。如果该文件已存在，文件指针将会放在文件的结尾。即新的内容将会被写入到已有内容之后。如果该文件不存在，创建新文件进行写入
with open('test.txt', 'a') as f:
    # 前面的open()方法需要自己关闭文件；f.close()；而with方法不需要自己关闭文件，无论是否出现异常，with都会自动帮助我们关闭文件
    f.write('43434343434343')
open5 = open('test.txt')
for line in open5:
    print('通过循环读取文件内容2：%s' % line)

# 9. seek(偏移量,[起始位置])：用来移动文件指针
open6 = open('test.txt')
for line in open6:
    print('通过循环读取文件内容3：%s' % line)
# 再次读取将读取不到任何值
for line in open6:
    print('通过循环读取文件内容31：%s' % line)
# 通过seek() 指定指针位置
open6.seek(0)
for line in open6:
    print('通过循环读取文件内容32：%s' % line)

# 10 . 引入内置模块 csv，进行 csv 文件操作
import csv
# 写入数据到 csv 文件
data = [['id', '姓名', '年龄', '身高'], [1, '秦', 27, 170.6], [2, '陈', 26, 175], [3, '何', 28, 175.3]]
# 注意：使用windows系统如果不加 newline=''，会出现空行的问题，mac系统不会出现。因为在默认状态下，在将字符串写入文件时，程序会将\n转换为系统默认的
#      行分隔符（即在windows操作系统下，为\r\n）。因此才会在windows系统中出现文件中的空行问题
with open('test.csv', 'w', newline='') as f:
    wr = csv.writer(f)
    wr.writerows(data)

# 读取 csv 文件
open7 = open('test.csv')
# 通过 csv.reader()读取文件，和前面提到的读取方式不同
reader = csv.reader(open7)
# 通过循环读取每行数据
for row in reader:
    print(row)


# 11. 操作excel 文件。需要安装 第三方工具包 openpyxl：pip3 install openpyxl
# 引入工作簿
from openpyxl import Workbook
# 创建工作簿
wb = Workbook()
# 一个工作簿默认有一个工作表
ws = wb.active
# 工作表默认标题为 Sheet，可以自行修改
print(ws.title)
ws.title = '默认工作表'
# 工作簿可以有多个工作表，自行创建如下
ws2 = wb.create_sheet('自创的工作表')
# 查看工作簿中的工作表名列表
print(wb.sheetnames)
# 在指定工作表中的列行中插入数据。例如下面的在默认工作表ws的 第 E 列，第 1 行 插入 111，和第 A 列，第 5 行 插入 5555
ws['E1'] = 111
ws['A5'] = 555
# 在自定义的工作表 ws2 中，通过 cell() 对指定单元格插入数据。
ws2.cell(row=2, column=2, value=22222)
# 通过循环语句操作多个单元格。注意 py 中 excel 的单元格是从 第一行 第一列 或者说 A1 开始的，而不是从第 0 行 0 列开始
datas = [['id', '姓名', '年龄', '身高'], [1, '秦', 27, 170.6], [2, '陈', 26, 175], [3, '何', 28, 175.3],
         [4, '秦4', 27, 170.6], [5, '陈5', 26, 175], [6, '何6', 28, 175.3]]
ws3 = wb.create_sheet('自创的工作表2')
limit = 1
for da in datas:
    li = 1
    for d in da:
        ws3.cell(limit, li, d)
        li += 1
    limit += 1
# 把上述内容保存在指定文件中，例如：example.xlsx
wb.save('example.xlsx')
